package com.wlyuan.open.scanner.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wlyuan.open.scanner.constant.AddressTypeEnum;
import com.wlyuan.open.scanner.dao.entity.AddrDO;
import com.wlyuan.open.scanner.dao.entity.BasicAreaDO;
import com.wlyuan.open.scanner.dao.mapper.AddrMapper;
import com.wlyuan.open.scanner.domain.address.Address;
import com.wlyuan.open.scanner.domain.address.AddressConvert;
import com.wlyuan.open.scanner.repository.AddressRepository;
import com.wlyuan.open.scanner.repository.BasicAreaRepository;
import com.wlyuan.open.scanner.repository.LinkManRepository;
import com.wlyuan.open.scanner.utils.BatchSelectUtils;
import com.wlyuan.open.scanner.utils.GroupCreateKey;
import com.wlyuan.open.scanner.utils.StreamUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AddressRepositoryImpl implements AddressRepository {

    private final AddrMapper addrMapper;
    private final LinkManRepository linkManRepository;
    private final BasicAreaRepository basicAreaRepository;

    @Override
    public Map<Long, List<Address>> getAddressMap(List<Long> customerIds, Integer addressType) {
        if (CollectionUtils.isEmpty(customerIds)) {
            return Collections.emptyMap();
        }
        return address(customerIds, addressType);
    }

    @Override
    public Map<Long, List<Address>> getAddress(Long sourceId, Integer addressType) {

        return address(Arrays.asList(sourceId), addressType);
    }

    private Map<Long, List<Address>> address(List<Long> sourceIds, Integer addressType) {
        //地址结果集处理，设置联系人，去重
        var list = process(sourceIds, addressType);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }
        var result = StreamUtils.convert(list, AddressConvert::convert);
        //线上承运方
        if (AddressTypeEnum.isOnline(addressType)) {
            //根据承运方ID分组
            return StreamUtils.groupBy(result, Address::getSupplierId);
        }
        //线下承运方
        if (AddressTypeEnum.isOffline(addressType)) {
            //根据承运方ID分组
            return StreamUtils.groupBy(result, Address::getSymbolId);
        }
        //根据客户ID分组
        return StreamUtils.groupBy(result, Address::getCustomerId);
    }

    @Override
    public Address getById(Long addressId) {
        return Optional.ofNullable(addressId).map(id -> {
            var data = addrMapper.selectById(id);
            return Optional.ofNullable(data).map(addr -> {
                processLinkMan(Arrays.asList(addr));
                return AddressConvert.convert(addr);
            }).orElse(null);
        }).orElse(null);
    }

    /**
     * 获取地址结果集
     *
     * @param sourceIds   客户ids,线上承运方ids,线下承运方ids
     * @param addressType 地址类型
     * @return
     */
    private List<AddrDO> process(List<Long> sourceIds, Integer addressType) {
        List<AddrDO> list = Collections.emptyList();
        if (AddressTypeEnum.isCustomer(addressType)) {
            list = getCustomerAddr(sourceIds);
        }
        if (AddressTypeEnum.isReceiving(addressType)) {
            list = getReceivingAddr(sourceIds);
        }
        if (AddressTypeEnum.isOnline(addressType)) {
            list = getSupplierAddr(sourceIds);
        }
        if (AddressTypeEnum.isOffline(addressType)) {
            list = getSymbolAddr(sourceIds);
        }
        //设置联系人
        processLinkMan(list);
        //同一个客户，根据省市区名称，联系人名称和电话 去重
        return distinctProvinceCityDistinct(list);
    }

    /**
     * 发货地址
     *
     * @param orderIds
     * @return
     */
    private List<AddrDO> getCustomerAddr(List<Long> orderIds) {
        //分批查询
        var list = BatchSelectUtils.batch(orderIds, this::selectCustomerAddr);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return list;
    }

    private List<AddrDO> selectCustomerAddr(List<Long> sourceIds) {
        QueryWrapper<AddrDO> queryWrapper = new QueryWrapper<>();
        if (sourceIds.size() > 1) {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.CUSTOMER.getValue()).eq(AddrDO::getAddrInvalid, 0).in(AddrDO::getAddrCustomerid, sourceIds);
        } else {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.CUSTOMER.getValue()).eq(AddrDO::getAddrInvalid, 0).eq(AddrDO::getAddrCustomerid, sourceIds.stream().findFirst().get());
        }
        queryWrapper.lambda().isNotNull(AddrDO::getAddrProvinceid).isNotNull(AddrDO::getAddrCityid).isNotNull(AddrDO::getAddrDistrictid);

        List<AddrDO> list = addrMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * 收货地址
     *
     * @param orderIds
     * @return
     */
    private List<AddrDO> getReceivingAddr(List<Long> orderIds) {
        //分批查询
        var list = BatchSelectUtils.batch(orderIds, this::selectReceivingAddr);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return list;
    }

    private List<AddrDO> selectReceivingAddr(List<Long> sourceIds) {
        QueryWrapper<AddrDO> queryWrapper = new QueryWrapper<>();
        if (sourceIds.size() > 1) {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.RECEIVINGADDRESS.getValue()).eq(AddrDO::getAddrInvalid, 0).in(AddrDO::getAddrCustomerid, sourceIds);
        } else {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.RECEIVINGADDRESS.getValue()).eq(AddrDO::getAddrInvalid, 0).eq(AddrDO::getAddrCustomerid, sourceIds.stream().findFirst().get());
        }

        queryWrapper.lambda().isNotNull(AddrDO::getAddrProvinceid).isNotNull(AddrDO::getAddrCityid).isNotNull(AddrDO::getAddrDistrictid);
        List<AddrDO> list = addrMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * 线上承运方地址
     *
     * @param orderIds
     * @return
     */
    private List<AddrDO> getSupplierAddr(List<Long> orderIds) {
        //分批查询
        var list = BatchSelectUtils.batch(orderIds, this::selectSupplierAddr);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return list;
    }

    private List<AddrDO> selectSupplierAddr(List<Long> sourceIds) {
        QueryWrapper<AddrDO> queryWrapper = new QueryWrapper<>();
        if (sourceIds.size() > 1) {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.ONLINE_CARRIER.getValue()).eq(AddrDO::getAddrInvalid, 0).in(AddrDO::getAddrSupplierid, sourceIds);
        } else {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.ONLINE_CARRIER.getValue()).eq(AddrDO::getAddrInvalid, 0).eq(AddrDO::getAddrSupplierid, sourceIds.stream().findFirst().get());
        }
        queryWrapper.lambda().isNotNull(AddrDO::getAddrProvinceid).isNotNull(AddrDO::getAddrCityid).isNotNull(AddrDO::getAddrDistrictid);

        List<AddrDO> list = addrMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * 线下承运方地址
     *
     * @param orderIds
     * @return
     */
    private List<AddrDO> getSymbolAddr(List<Long> orderIds) {
        //分批查询
        var list = BatchSelectUtils.batch(orderIds, this::selectSymbolAddr);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        return list;
    }

    private List<AddrDO> selectSymbolAddr(List<Long> sourceIds) {
        QueryWrapper<AddrDO> queryWrapper = new QueryWrapper<>();
        if (sourceIds.size() > 1) {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.OFFLINE_CARRIER.getValue()).eq(AddrDO::getAddrInvalid, 0).in(AddrDO::getAddrSymbolid, sourceIds);
        } else {
            queryWrapper.lambda().eq(AddrDO::getAddrType, AddressTypeEnum.OFFLINE_CARRIER.getValue()).eq(AddrDO::getAddrInvalid, 0).eq(AddrDO::getAddrSymbolid, sourceIds.stream().findFirst().get());
        }
        queryWrapper.lambda().isNotNull(AddrDO::getAddrProvinceid).isNotNull(AddrDO::getAddrCityid).isNotNull(AddrDO::getAddrDistrictid);

        List<AddrDO> list = addrMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * 同一个客户，根据省市区名称，联系人名称和电话 去重
     *
     * @param list
     * @return
     */
    private List<AddrDO> distinctProvinceCityDistinct(List<AddrDO> list) {
        return StreamUtils.distinct(list, Comparator.comparing(o ->
                GroupCreateKey.createKey(String.valueOf(o.getAddrCustomerid()), o.getAddrProvincename(), o.getAddrCityname(), o.getAddrDistrictname(), o.getAddrDesc(), o.getContactName(), o.getAddrPhone())), true);
    }

    /**
     * 设置地址联系人
     *
     * @param list
     */
    private void processLinkMan(List<AddrDO> list) {
        var addrIds = list.stream().map(AddrDO::getAddrId).filter(x -> x != null).collect(Collectors.toList());
        //查询地址id对应联系人信息
        var linkMapMap = linkManRepository.getLinkManByAddrIds(addrIds);
        var areaMap = getArea(list);
        list.stream().forEach(source -> {
            source.setAddrProvincename(Optional.ofNullable(areaMap.get(source.getAddrProvinceid())).map(BasicAreaDO::getAreaName).orElse(""));
            source.setAddrCityname(Optional.ofNullable(areaMap.get(source.getAddrCityid())).map(BasicAreaDO::getAreaName).orElse(""));
            source.setAddrDistrictname(Optional.ofNullable(areaMap.get(source.getAddrDistrictid())).map(BasicAreaDO::getAreaName).orElse(""));

            var linkMan = linkMapMap.get(source.getAddrId());
            source.setContactName("");
            source.setAddrPhone("");
            Optional.ofNullable(linkMan).ifPresent(link -> {
                source.setContactName(link.getLinkmanName());
                source.setAddrPhone(link.getLinkmanPhone());
                source.setIsDefault(link.getLinkmanDefault());
            });
        });
    }

    private Map<Long, BasicAreaDO> getArea(List<AddrDO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }
        var province = StreamUtils.mapList(list, AddrDO::getAddrProvinceid);
        var city = StreamUtils.mapList(list, AddrDO::getAddrCityid);
        var distinct = StreamUtils.mapList(list, AddrDO::getAddrDistrictid);
        return basicAreaRepository.getAreaMap(province, city, distinct);

    }
}
